package com.jzo2o.orders.base.handler;

import cn.hutool.db.DbRuntimeException;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.orders.base.enums.OrderPayStatusEnum;
import com.jzo2o.orders.base.enums.OrderStatusEnum;
import com.jzo2o.orders.base.model.dto.OrderSnapshotDTO;
import com.jzo2o.orders.base.model.dto.OrderUpdateStatusDTO;
import com.jzo2o.orders.base.service.IOrdersCommonService;
import com.jzo2o.statemachine.core.StatusChangeEvent;
import com.jzo2o.statemachine.core.StatusChangeHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * 这是一个动作,也要实现状态机对应的动作接口implements StatusChangeHandler
 * 状态机不理解,,就从头看下各个概念,比如事件,动作,现态,次态
 * @author Mr.M
 * @version 1.0
 * @description 支付成功执行的动作
 * 这个动作应该就是支付成功后,,将"待支付"状态修改成"派单中"
 * @date 2023/12/19 10:11
 */
@Component("order_payed")//指定了容器中bean的名称,规则是：状态机名称_事件名称
    //订单服务,所以这里状态机名称就叫了"order",事件名称,得去OrderStatusChangeEventEnum.java这个定义的事件类中找,
    //当前是支付成功的动作,所以上面事件类定义的属性,就是"PAYED",对应的code代码是"payed",所以上面容器中按照指定规则的bean名称就有了
@Slf4j
public class OrderPayedHandler implements StatusChangeHandler<OrderSnapshotDTO> {
    //OrderSnapshotDTO这个是刚才我们定义的快照,,忘了回顾视频,day08_02

    @Resource
    private IOrdersCommonService ordersCommonService;


    /**
     * 订单支付处理逻辑
     * @param bizId  业务id
     * @param statusChangeEventEnum  状态变更事件
     * @param bizSnapshot  快照
     */
    @Override
    public void handler(String bizId, StatusChangeEvent statusChangeEventEnum, OrderSnapshotDTO bizSnapshot) {
        log.info("支付成功事件发布执行此动作....");
        
        //修改订单状态和支付状态
            // 统一对订单状态和支付状态进行更新，将订单状态由待支付改为派单中
        //因为下面updateStatus要传入OrderUpdateStatusDTO对象,所以需要进行封装; 对应的字段要更新的更新
        //需要注意: 很多参数老师都是直接从快照bizSnapshot取出的,,那前面OrdersCreateServiceImpl.java里面的paySuccess方法中肯定要封装好这个快照类OrderSnapshotDTO
        OrderUpdateStatusDTO orderUpdateStatusReqDTO = new OrderUpdateStatusDTO();
        orderUpdateStatusReqDTO.setId(bizSnapshot.getId());//订单id
        //因为这个动作,很明确就只是从"待支付"支付成功,变为"派单中",所以下面对应的两个状态,老师直接写死了
            //那我是不是可以理解,一个方法,就类似一个动作;因为这里也是只表示了支付成功的两种状态的转变,,那别的状态转变是不是要写单独的动作类
        orderUpdateStatusReqDTO.setOriginStatus(OrderStatusEnum.NO_PAY.getStatus());//原始状态待支付
        orderUpdateStatusReqDTO.setTargetStatus(OrderStatusEnum.DISPATCHING.getStatus());//目标状态为派单中
        orderUpdateStatusReqDTO.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());//支付成功,这个是支付状态,上面的是订单状态
        //老师说当前这个动作类,就表示支付成功,,所以上面代码状态就可以直接写成支付成功

        orderUpdateStatusReqDTO.setTradingOrderNo(bizSnapshot.getTradingOrderNo());//交易单号
        orderUpdateStatusReqDTO.setTransactionId(bizSnapshot.getThirdOrderId());//第三方支付平台的交易单号
        orderUpdateStatusReqDTO.setPayTime(bizSnapshot.getPayTime());//支付时间
        orderUpdateStatusReqDTO.setTradingChannel(bizSnapshot.getTradingChannel());//支付渠道

        //这个updateStatus应该是这个ordersCommonService工具类老师定义过,直接提供的
            //不过更新订单表的状态,,原来OrdersCreateServiceImpl.java中的paySuccess方法中,更新的就是orders表,这里怎么变成这个orderUpdateStatusReqDTO了
            //我明白了,,你跳进去这个updateStatus里面,,里面是对orders表进行的状态更新,,这种代码写的堵得慌
        //下面方法返回结果只有1或者0,,成功就返回1
        Integer integer = ordersCommonService.updateStatus(orderUpdateStatusReqDTO);
        if(integer<1){
            //下面这里输出了对应的订单号,,是为了便于追踪异常
            throw new CommonException("订单"+bizSnapshot.getId()+"支付成功事件执行动作失败");
        }
        
        //修改订单状态和支付状态
        //把上面代码优化成builder构造器实现,,其实一样,我还是想用上面的,,有注释
        //OrderUpdateStatusDTO orderUpdateStatusDTO = OrderUpdateStatusDTO.builder().id(Long.valueOf(bizId))
        //        .originStatus(OrderStatusEnum.NO_PAY.getStatus())
        //        .targetStatus(OrderStatusEnum.DISPATCHING.getStatus())
        //        .payStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus())
        //        .payTime(LocalDateTime.now())
        //        .tradingOrderNo(bizSnapshot.getTradingOrderNo())
        //        .transactionId(bizSnapshot.getThirdOrderId())
        //        .tradingChannel(bizSnapshot.getTradingChannel())
        //        .build();
        //int result = ordersCommonService.updateStatus(orderUpdateStatusDTO);
        //if (result <= 0) {
        //    throw new DbRuntimeException("支付事件处理失败");
        //}
    }
}
